package cn.tedu.tmall.passport.service.impl;

import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.ex.ServiceException;
import cn.tedu.tmall.common.pojo.po.UserStatePO;
import cn.tedu.tmall.common.pojo.security.CurrentPrincipal;
import cn.tedu.tmall.passport.dao.cache.IUserCacheRepository;
import cn.tedu.tmall.passport.dao.persist.repository.IUserRepository;
import cn.tedu.tmall.passport.pojo.param.UserLoginInfoParam;
import cn.tedu.tmall.passport.pojo.vo.UserLoginInfoVO;
import cn.tedu.tmall.passport.pojo.vo.UserLoginResultVO;
import cn.tedu.tmall.passport.service.IUserService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl implements IUserService {

    @Value("${tmall.jwt.secret-key}")
    private String secretKey;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserRepository userRepository;
    @Autowired
    private IUserCacheRepository userCacheRepository;

    @Override
    public UserLoginResultVO login(UserLoginInfoParam userLoginInfoParam, String remoteAddr, String userAgent) {
        // 从参数中获取用户名
        String username = userLoginInfoParam.getUsername();
        // 调用Repository根据用户名查询用户信息
        UserLoginInfoVO loginInfo = userRepository.getLoginInfoByUsername(username);
        // 判断查询结果是否为null
        if (loginInfo == null) {
            // 是：抛出异常（unauthorized:40100）：用户名或密码错误
            String message = "登录失败，用户名或密码错误！【1】";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        // 判断查询结果中的enable是否不为1
        if (loginInfo.getEnable() != 1) {
            // 是：抛出异常（unauthorized_disabled:40101）：账号已经被禁用
            String message = "登录失败，此账号已经被禁用！";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message);
        }

        // 从参数中获取密码
        String password = userLoginInfoParam.getPassword();
        // 判断查询结果中的密码与参数密码是否不匹配
        if (!passwordEncoder.matches(password, loginInfo.getPassword())) {
            // 是：抛出异常（unauthorized:40100）：用户名或密码错误
            String message = "登录失败，用户名或密码错误！【2】";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }

        // TODO 向登录日志表中插入数据
        // TODO 更新当前用户的登录次数、最后登录时间、登录IP地址

        // 向Redis中写入此用户的启用状态与权限列表
        List<String> loginInfoAuthorities = loginInfo.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(loginInfoAuthorities);
        UserStatePO userStatePO = new UserStatePO();
        userStatePO.setEnable(1);
        userStatePO.setAuthoritiesJsonString(authoritiesJsonString);
        userCacheRepository.saveUserState(loginInfo.getId(), userStatePO);

        // 创建返回的对象
        UserLoginResultVO loginResult = new UserLoginResultVO();
        loginResult.setId(loginInfo.getId());
        loginResult.setUsername(loginInfo.getUsername());
        loginResult.setAvatar(loginInfo.getAvatar());
        loginResult.setAuthorities(loginInfo.getAuthorities());

//        // 准确权限列表，需要是符合框架要求的数据格式，即Collection<? extends GrantedAuthority> authorities
//        List<String> loginInfoAuthorities = loginInfo.getAuthorities();
//        List<GrantedAuthority> authorities = new ArrayList<>();
//        for (String authority : loginInfoAuthorities) {
//            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(authority);
//            authorities.add(grantedAuthority);
//        }
//
//        // 准备当事人数据
//        CurrentPrincipal principal = new CurrentPrincipal();
//        principal.setId(loginInfo.getId());
//        principal.setUsername(loginInfo.getUsername());
//
//        // 向SecurityContext中存入Authentication
//        Authentication authentication
//                = new UsernamePasswordAuthenticationToken(principal, null, authorities);
//        SecurityContext securityContext = SecurityContextHolder.getContext();
//        securityContext.setAuthentication(authentication);

        // 将用户的ID与用户名用于生成JWT，并存入到响应对象中
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", loginInfo.getId());
        claims.put("username", loginInfo.getUsername());
        claims.put("remoteAddr", remoteAddr);
        claims.put("userAgent", userAgent);
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                // Done
                .compact();
        loginResult.setToken(jwt);

        // 返回
        return loginResult;
    }

    @Override
    public void logout(CurrentPrincipal currentPrincipal) {
        userCacheRepository.deleteUserState(currentPrincipal.getId());
    }

}
